package com.uft.was.app;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.Security;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import com.ibm.ws.scripting.WasxShell;
import com.ibm.wsspi.ssl.RetrieveSignersHelper;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.uft.remote.UftRemote;
import com.uft.utils.UftUtils;

public class WasDeployCommand extends Thread {
	private  static Logger  logger = Logger.getLogger(WasDeployCommand.class);
	private WasAppManager wasAppMgr;
	private String soapCfgURL;	
	private String sslCfgURL;
	private String wasInstallPath;
	private String rootFolder;
	private String javacmd;
	private String deployScript="DeployApp.sh";
	private String soapRequestTimeout="50";
	private String knownHostFile;
	private String sshUsername;
	private String sshPassword;
	private String workingDir;
	private String sudoCommand;
	private Map<String, String> env ;
	private HashMap<String, String> arguments;
	private boolean remoteExecute=false;
	
	public WasDeployCommand(WasAppManager wasAppManager){
		this.wasAppMgr=wasAppManager;
		soapCfgURL = "soap.client.props";
	    sslCfgURL = "ssl.client.props";
	    rootFolder=System.getProperty("user.home");
	    wasInstallPath=rootFolder;
	    env= new HashMap<String,String>();
	}
	public void run() {
		// TODO Auto-generated method stub
		logger.info("Running the task: remote "+wasAppMgr.isRemoteExecute());
		if(wasAppMgr.isRemoteExecute()){
			remoteExecute();
		}else{
			localExecute();
		}
		
		
	}
	
	private void localExecute() {
		// TODO Auto-generated method stub
		if(rootFolder != null)
        {
           // System.setProperty("WAS_HOME", rootFolder);
            System.setProperty("USER_INSTALL_ROOT", (new StringBuilder(String.valueOf(rootFolder))).append("/").toString());
            System.setProperty("user.install.root", (new StringBuilder(String.valueOf(rootFolder))).append("/").toString());
            System.setProperty("user.root", (new StringBuilder(String.valueOf(rootFolder))).append("/properties").toString());
        }
		if(rootFolder != null && soapCfgURL.indexOf("file:") < 0 && sslCfgURL.indexOf("file:") < 0){
			soapCfgURL = (new StringBuilder("file:")).append(rootFolder).append("/properties/").append(soapCfgURL).toString();
            sslCfgURL = (new StringBuilder("file:")).append(rootFolder).append("/properties/").append(sslCfgURL).toString();
		}
		 String classPath = (new StringBuilder(String.valueOf(rootFolder))).append("/lib/com.ibm.ws.admin.client_7.0.0.jar").toString();
         classPath = (new StringBuilder(String.valueOf(classPath))).append(";").append(rootFolder).append("/optionalLibraries/jython/jython.jar").toString();
         classPath = (new StringBuilder(String.valueOf(classPath))).append(";").append(rootFolder).append("lib/com.ibm.ws.security.crypto.jar").toString();
         System.out.println("soapCfgURL. "+soapCfgURL);
         System.out.println("sslCfgURL. "+sslCfgURL);
         System.setProperty("com.ibm.SOAP.ConfigURL", soapCfgURL);
         System.setProperty("com.ibm.SSL.ConfigURL", sslCfgURL);
         System.setProperty("com.ibm.websphere.thinclient", "true");
         System.setProperty("org.apache.soap.util.net.SSLUtils.buildSSLSocket.timeout", "6000000");
         System.setProperty("com.ibm.SOAP.requestTimeout", "6000000");
         System.setProperty("sun.net.client.defaultConnectTimeout", "6000000");
         System.setProperty("sun.rmi.transport.proxy.connectTimeout", "6000000");
         System.setProperty("org.apache.soap.util.net.SSLUtils.buildSSLSocket.timeout", "6000000");
         System.setProperty("com.ibm.ws.management.connector.soap.keepAlive", "true");
         Security.setProperty("ssl.SocketFactory.provider", "com.ibm.jsse2.SSLSocketFactoryImpl");
         Security.setProperty("ssl.ServerSocketFactory.provider", "com.ibm.jsse2.SSLServerSocketFactoryImpl");
         Security.setProperty("ssl.SocketFactory.provider", "com.sun.net.ssl.internal.ssl.SSLSocketFactoryImpl");
         Security.setProperty("ssl.ServerSocketFactory.provider", "com.sun.net.ssl.internal.ssl.SSLServerSocketFactoryImpl");
         String args = "";
         StringBuilder str=new StringBuilder();
         str.append(" -connType SOAP -host ").append(wasAppMgr.getHostname()).append(" -port ").append(wasAppMgr.getPort()).append(" -lang jython");
         if(wasAppMgr.isSecurity()){
         	str.append(" -user ").append(wasAppMgr.getDmgrUsername()).append(" -password ").append(wasAppMgr.getDmgrPassword());
         }
         str.append(" -f ").append(deployScript).append("");
	     
	     str.append(" ").append(getParameters());
         args=str.toString();
         String mainClass = "com.ibm.ws.scripting.WasxShell";
         System.out.println(args);
         String cmd ="";
         if(System.getProperty("java.vendor").contains("IBM")){
        	 cmd = (new StringBuilder()).append(javacmd).append(" \"-Xgcpolicy:gencon\" \"-Xshareclasses:name=perfTool\" \"-Xms256m\" \"-Xmx256m\" \"-Xj9\" \"-Xquickstart\" \"-Dcom.ibm.SOAP.ConfigURL=")
			 			.append(soapCfgURL)
			 			.append("\" \"-Dcom.ibm.SSL.ConfigURL=")
			 			.append(sslCfgURL)
			 			.append("\" \"-Dwas.install.root=")
			 			.append(rootFolder)
			 			.append("\" \"-Duser.root=")
			 			.append(rootFolder)
			 			.append("etc/")
			 			.append("\" \"-Dsun.net.client.defaultConnectTimeout=600000")
			 			.append("\" \"-Dsun.rmi.transport.proxy.connectTimeout=600000")
			 			.append("\" \"-Dorg.apache.soap.util.net.SSLUtils.buildSSLSocket.timeout=600000")
			 			.append("\" \"-Dcom.ibm.ws.management.connector.soap.keepAlive=true")
			 			.append("\" \"-Dcom.ibm.websphere.thinclient=true")
			 			.append("\" \"-Dpython.home=").append(rootFolder)
			 			.append("optionalLibraries/jython")
			 			.append("\" -cp \"")
			 			.append(classPath)
			 			.append("\" ")
			 			.append(mainClass)
			 			.append(args).toString();
         }else{
        	 cmd=(new StringBuilder()).append(javacmd)
        			 .append(" -Xms256m -Xmx256m -Dcom.ibm.SOAP.ConfigURL=").append(soapCfgURL)
        			 .append(" -Dcom.ibm.SSL.ConfigURL=").append(sslCfgURL)
        			 .append(" -Dwas.install.root=").append(rootFolder)
        			 .append(" -Duser.root=").append(rootFolder)
        			 .append(" -Dsun.net.client.defaultConnectTimeout=600000")
        			 .append(" -Dsun.rmi.transport.proxy.connectTimeout=600000")
        			 .append(" -Dorg.apache.soap.util.net.SSLUtils.buildSSLSocket.timeout=600000")
        			 .append(" -Dcom.ibm.ws.management.connector.soap.keepAlive=true")
        			 .append(" -Dcom.ibm.websphere.thinclient=true")
        			 .append(" -Dpython.home=").append(rootFolder).append("/optionalLibraries/jython")
        			 .append(" -cp ").append(rootFolder).append("/com.ibm.ws.admin.client_7.0.0.jar:").append(rootFolder).append("/optionalLibraries/jython/jython.jar:").append(rootFolder).append("/com.ibm.ws.security.crypto.jar")
        			 .append(" "+mainClass).append(" ").append(args)
        			 .toString();
         }
         System.out.println("Command: "+cmd);
         File file= new File(deployScript);
         if(file.isFile()){
        	 wasAppMgr.setRunning(true);
        	 wasAppMgr.setStartTime(Calendar.getInstance());
        	 Process process;
			try {
				process = Runtime.getRuntime().exec(cmd.trim(), null, (new File(deployScript)).getParentFile());
				 InputStream stdin = process.getInputStream();
	             InputStream stderr = process.getErrorStream();
	             Thread tIn = new Thread(new ConsoleSimulator(stdin, wasAppMgr.getOutputBuffer(),0));
	             Thread tErr = new Thread(new ConsoleSimulator(stderr, wasAppMgr.getErrorBuffer(), 1));
	             tIn.start();
	             tErr.start();
	             int exitCode = process.waitFor();
	 			wasAppMgr.setErrorCode(exitCode);
	            wasAppMgr.setEndTime(Calendar.getInstance());
	            wasAppMgr.setRunning(false);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				wasAppMgr.setErrorCode(-1);
				wasAppMgr.getErrorBuffer().append(e.getMessage());
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				wasAppMgr.setErrorCode(-1);
				wasAppMgr.getErrorBuffer().append(e.getMessage());
			} finally{
				wasAppMgr.setRunning(false);
			}
        	
         }else{
        	 System.err.println("File does't exist"+deployScript);
         }
         
			
	}
	/**
	 * use JSCH API exec to executed the scripts remote. Used for UNIX application with ssh enabled
	 * The remote server needs to be authorized in knowhostfule.
	 */
	public void remoteExecute(){
		try {
			JSch jsch = new JSch();
			wasAppMgr.setRunning(true);
			wasAppMgr.setStartTime(Calendar.getInstance());
			logger.info("Connecting to SSH :"+wasAppMgr.getHostname()+" Username: "+sshUsername);
			Session session=jsch.getSession(sshUsername,wasAppMgr.getHostname(),22);
			session.setPassword(sshPassword);
			session.setConfig("StrictHostKeyChecking", "no");
			session.connect();
			logger.info("Connected OK");
			ChannelExec channel=(ChannelExec)session.openChannel("exec");
			
			if(env != null){
				Iterator keys=env.keySet().iterator();
				while(keys.hasNext()){
					String name=(String)keys.next();
					String value=env.get(name);
					logger.debug("Name: "+name+" /Value: "+value);
					channel.setEnv(name,value);
				}
			}
			String cmd="";
			if(sudoCommand  != null){
				if(!sudoCommand.equalsIgnoreCase("")){
					cmd=sudoCommand;
					cmd+=" ";
					channel.setPty(true);
				}
			}
			cmd+=deployScript;
			String args= getParameters();
			if(args != null && !args.equalsIgnoreCase("")){
				cmd+=" "+args;
			}
			logger.info("cmd: "+cmd);
			channel.setCommand(cmd);
			InputStream in=channel.getInputStream();
			InputStream err=channel.getErrStream();	
			channel.connect();
			byte[] tmp=new byte[1024];
			while(true){
				while(in.available() > 0){
					int i=in.read(tmp,0,1024);
					if(i<0) break;
					wasAppMgr.getOutputBuffer().append(new String(tmp,0,i));
				}
				while(err.available() > 0){
					int i=err.read(tmp,0,1024);
					if(i<0) break;
					wasAppMgr.getErrorBuffer().append(new String(tmp,0,i));
				}
				if(channel.isClosed()){
					wasAppMgr.setErrorCode(channel.getExitStatus());
					break;
				}
				try{Thread.sleep(1000);}catch(Exception e){};
			}
			wasAppMgr.setErrorCode(channel.getExitStatus());
            channel.disconnect();
            session.disconnect();
            wasAppMgr.setEndTime(Calendar.getInstance());
            wasAppMgr.setRunning(false);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			wasAppMgr.setErrorCode(-1);
			wasAppMgr.getErrorBuffer().append(e.getMessage());
		}finally{
			wasAppMgr.setRunning(false);
		}
			
	}
	private String getParameters() {
		// TODO Auto-generated method stub
		String result="";
		if(arguments != null){
			if(arguments.containsKey("email")){
				if(!arguments.get("email").equalsIgnoreCase("")){
					result+=" -s "+arguments.get("email");
				}
			}
			if(arguments.containsKey("deployFile")){
				if(!arguments.get("deployFile").equalsIgnoreCase("")){
					result+=" -e "+arguments.get("deployFile");
				}
			}
			if(arguments.containsKey("autoRestart")){
				if(arguments.get("autoRestart").equalsIgnoreCase("true")){
					result+=" -r true";
				}
			}
			result+=" "+wasAppMgr.getServerName();
		}
		return result;
	}
	public List<String> getDeployFiles() {
		// TODO Auto-generated method stub
		List<String> result= new ArrayList<String>();
		if(wasAppMgr.getScriptPath() != null && !wasAppMgr.getScriptPath().equalsIgnoreCase("")){
			String responseFilePath=wasAppMgr.getScriptPath();
			logger.debug("responseFilePath : "+responseFilePath);
			responseFilePath+=System.getProperty("file.separator")+
					"responsefiles"+System.getProperty("file.separator")+
					"deploy"+System.getProperty("file.separator");
			logger.info("responseFile deploy File Path : "+responseFilePath);
			String applicationName=UftUtils.getApplicationName(wasAppMgr.getServerName(),wasAppMgr.getServerSuffix(), wasAppMgr.getServerPrefix());
			responseFilePath+=applicationName;
			logger.debug("responseFile deploy File : "+responseFilePath);
			if(wasAppMgr.isRemoteExecute()){
				logger.debug("Remote Execution is enabled");
				
				UftRemote uftRemote= new UftRemote(wasAppMgr.getHostname(), sshUsername, sshPassword, 22,knownHostFile);
				List<String> fileRList=uftRemote.getFileList(responseFilePath);
				for (int i = 0; i < fileRList.size(); i++) {
					 String fileName = fileRList.get(i);
					 if (fileName.endsWith(".txt") || fileName.endsWith(".TXT")){
						 File file = new File(fileName);
						 String fileNameWithExt = file.getName();
						 String[] array= fileNameWithExt.split("_");
						 if(array.length > 0){
							 String  earFile=array[0];
							 if( earFile != null && !earFile.equalsIgnoreCase("")){
								 result.add(earFile);
							 }
						 }
					 }
				}
			}else{
				logger.debug("Local is enabled");
				File file = new File(responseFilePath);
				if(file.isDirectory()){
					 File[] listOfFiles = file.listFiles(); 
					 for (int i = 0; i < listOfFiles.length; i++) {
						 String fileName = listOfFiles[i].getName();
						 if (fileName.endsWith(".txt") || fileName.endsWith(".TXT")){
							String[] array= fileName.split("_");
							if(array.length > 0){
								String  earFile=array[0];
								if( earFile != null && !earFile.equalsIgnoreCase("")){
									result.add(earFile);
								}
							}
						 }
							 
					 }
				}
			}
			
			
		}else{
			logger.warn("Script Path is not Found for this server :"+wasAppMgr.getServerName());
		}
		
		return result;
	}
	 public void initializeEnv(){
		 System.setProperty("com.ibm.SOAP.ConfigURL", soapCfgURL);
	     System.setProperty("com.ibm.SSL.ConfigURL", sslCfgURL);
	     System.setProperty("org.apache.soap.util.net.SSLUtils.buildSSLSocket.timeout", "6000000");
	     System.setProperty("com.ibm.SOAP.requestTimeout", "180");
	     System.setProperty("sun.net.client.defaultConnectTimeout", "180");
	     System.setProperty("sun.rmi.transport.proxy.connectTimeout", "180");
	     System.setProperty("com.ibm.ws.management.connector.soap.keepAlive", "true");
	     System.setProperty("com.ibm.websphere.thinclient", "true");
	     System.setProperty("was.install.root", wasInstallPath);
         System.setProperty("user.root", (new StringBuilder(String.valueOf(wasInstallPath))).append("/etc/").toString());
	 }
	public String getSoapCfgURL() {
		return soapCfgURL;
	}
	public void setSoapCfgURL(String soapCfgURL) {
		this.soapCfgURL = soapCfgURL;
	}
	public String getSslCfgURL() {
		return sslCfgURL;
	}
	public void setSslCfgURL(String sslCfgURL) {
		this.sslCfgURL = sslCfgURL;
	}
	public String getWasInstallPath() {
		return wasInstallPath;
	}
	public void setWasInstallPath(String wasInstallPath) {
		this.wasInstallPath = wasInstallPath;
	}
	public String getRootFolder() {
		return rootFolder;
	}
	public void setRootFolder(String rootFolder) {
		this.rootFolder = rootFolder;
	}
	public String getJavacmd() {
		return javacmd;
	}
	public void setJavacmd(String javacmd) {
		this.javacmd = javacmd;
	}
	public String getDeployScript() {
		return deployScript;
	}
	public void setDeployScript(String deployScript) {
		this.deployScript = deployScript;
	}
	public String getSoapRequestTimeout() {
		return soapRequestTimeout;
	}
	public void setSoapRequestTimeout(String soapRequestTimeout) {
		this.soapRequestTimeout = soapRequestTimeout;
	}
	public String getKnownHostFile() {
		return knownHostFile;
	}
	public void setKnownHostFile(String knownHostFile) {
		this.knownHostFile = knownHostFile;
	}
	public String getSshUsername() {
		return sshUsername;
	}
	public void setSshUsername(String sshUsername) {
		this.sshUsername = sshUsername;
	}
	public String getSshPassword() {
		return sshPassword;
	}
	public void setSshPassword(String sshPassword) {
		this.sshPassword = sshPassword;
	}
	public String getWorkingDir() {
		return workingDir;
	}
	public void setWorkingDir(String workingDir) {
		this.workingDir = workingDir;
	}
	public String getSudoCommand() {
		return sudoCommand;
	}
	public void setSudoCommand(String sudoCommand) {
		this.sudoCommand = sudoCommand;
	}
	public Map<String, String> getEnv() {
		return env;
	}
	public void setEnv(Map<String, String> env) {
		this.env = env;
	}
	public boolean isRemoteExecute() {
		return remoteExecute;
	}
	public void setRemoteExecute(boolean remoteExecute) {
		this.remoteExecute = remoteExecute;
	}
	public HashMap<String, String> getArguments() {
		return arguments;
	}
	public void setArguments(HashMap<String, String> arguments) {
		this.arguments = arguments;
	}
	
	
	 
}
